﻿// ------------------------------------------------------------------------------
// <copyright file="CharmSettingFlyout.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.
//
//    This program is free software; you can redistribute it and/or
//    modify it under the terms of the GNU General Public License
//    as published by the Free Software Foundation version 2
//    of the License.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    http://www.gnu.org/licenses/gpl-2.0.html
//
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.Controls
{
    using System;
    using Windows.Foundation;
    using Windows.UI.ApplicationSettings;
    using Windows.UI.Text;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Animation;

    /// <summary>
    /// Charm setting fly out control
    /// </summary>
    public class CharmSettingFlyout : ContentControl, IDisposable
    {
        /// <summary>
        /// Using a DependencyProperty as the backing store for Fly out Width.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty FlyoutWidthProperty =
            DependencyProperty.Register("FlyoutWidth", typeof(CharmSettingFlyoutWidth), typeof(CharmSettingFlyout), new PropertyMetadata(CharmSettingFlyoutWidth.Narrow, CharmSettingFlyout.OnSettingFlyoutWidth));

        /// <summary>
        /// Using a DependencyProperty as the backing store for Icon.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(ImageSource), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderText.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderTextProperty =
            DependencyProperty.Register("HeaderText", typeof(string), typeof(CharmSettingFlyout), new PropertyMetadata("Heading"));

        /// <summary>
        /// Using a DependencyProperty as the backing store for TransitionOffset.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty TransitionOffsetProperty =
            DependencyProperty.Register("TransitionOffset", typeof(double), typeof(CharmSettingFlyout), new PropertyMetadata(100));

        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderBackground.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderBackgroundProperty =
            DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderForeground.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderForegroundProperty =
            DependencyProperty.Register("HeaderForeground", typeof(Brush), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for BackButtonForeground.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty BackButtonForegroundProperty =
            DependencyProperty.Register("BackButtonForeground", typeof(Brush), typeof(CharmSettingFlyout), new PropertyMetadata(null));
        
        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderFontFamily.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderFontFamilyProperty =
            DependencyProperty.Register("HeaderFontFamily", typeof(FontFamily), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderFontSize.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderFontSizeProperty =
            DependencyProperty.Register("HeaderFontSize", typeof(double), typeof(CharmSettingFlyout), new PropertyMetadata(null));
        
        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderFontStyle.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderFontStyleProperty =
            DependencyProperty.Register("HeaderFontStyle", typeof(FontStyle), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for HeaderRenderTransform.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty HeaderRenderTransformProperty =
            DependencyProperty.Register("HeaderRenderTransform", typeof(Transform), typeof(CharmSettingFlyout), new PropertyMetadata(null));

        /// <summary>
        /// Pop up
        /// </summary>
        private Popup popup;

        /// <summary>
        /// Initializes a new instance of the <see cref="CharmSettingFlyout" /> class
        /// </summary>
        public CharmSettingFlyout()
        {
            this.DefaultStyleKey = typeof(CharmSettingFlyout);
        }
        
        /// <summary>
        /// Initializes a new instance of the <see cref="CharmSettingFlyout" /> class
        /// </summary>
        /// <param name="content">The content control</param>
        public CharmSettingFlyout(UserControl content)
            : this(content, CharmSetting.Animation)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CharmSettingFlyout" /> class
        /// </summary>
        /// <param name="content">The content control</param>
        /// <param name="animation">Animation type</param>
        public CharmSettingFlyout(UserControl content, CharmSettingAnimation animation)
            : this()
        {
            if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
            {
                return;
            }

            this.Loaded += this.OnLoaded;

            this.popup = new Popup();
            this.popup.Closed += this.OnPopupClosed;
            this.popup.Opened += this.OnPopupOpened;
            this.popup.IsLightDismissEnabled = true;
            this.popup.Opacity = 1;
            this.popup.Child = this;

            this.popup.Width = (double)this.FlyoutWidth;
            this.popup.Height = Window.Current.Bounds.Height;

            this.Width = (double)this.FlyoutWidth;
            this.Height = Window.Current.Bounds.Height;

            double trasitionOffSet = SettingsPane.Edge == SettingsEdgeLocation.Right ? 100 : -100;

            if (animation == CharmSettingAnimation.Flyout)
            {
                this.TransitionOffset = 0;

                this.popup.ChildTransitions = new TransitionCollection();
                this.popup.ChildTransitions.Add(new EntranceThemeTransition() { FromHorizontalOffset = trasitionOffSet });
            }
            else
            {
                this.TransitionOffset = trasitionOffSet;

                content.Transitions = new TransitionCollection();
                content.Transitions.Add(new EntranceThemeTransition() { FromHorizontalOffset = trasitionOffSet });
            }

            this.Content = content;
        }

        /// <summary>
        /// Gets or sets header text foreground color
        /// </summary>
        public Brush HeaderForeground
        {
            get { return (Brush)this.GetValue(HeaderForegroundProperty); }
            set { this.SetValue(HeaderForegroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets Charm setting small icon
        /// </summary>
        public ImageSource Icon
        {
            get { return (ImageSource)this.GetValue(IconProperty); }
            set { this.SetValue(IconProperty, value); }
        }

        /// <summary>
        /// Gets or sets Header text
        /// </summary>
        public string HeaderText
        {
            get { return (string)this.GetValue(HeaderTextProperty); }
            set { this.SetValue(HeaderTextProperty, value); }
        }

        /// <summary>
        /// Gets or sets transition offset
        /// </summary>
        public double TransitionOffset
        {
            get { return (double)this.GetValue(TransitionOffsetProperty); }
            set { this.SetValue(TransitionOffsetProperty, value); }
        }

        /// <summary>
        /// Gets or sets header background color
        /// </summary>
        public Brush HeaderBackground
        {
            get { return (Brush)this.GetValue(HeaderBackgroundProperty); }
            set { this.SetValue(HeaderBackgroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets Charm setting width width
        /// </summary>
        public CharmSettingFlyoutWidth FlyoutWidth
        {
            get { return (CharmSettingFlyoutWidth)this.GetValue(FlyoutWidthProperty); }
            set { this.SetValue(FlyoutWidthProperty, value); }
        }

        /// <summary>
        /// Gets or sets back button foreground
        /// </summary>
        public Brush BackButtonForeground
        {
            get { return (Brush)this.GetValue(BackButtonForegroundProperty); }
            set { this.SetValue(BackButtonForegroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets header font family
        /// </summary>
        public FontFamily HeaderFontFamily
        {
            get { return (FontFamily)this.GetValue(HeaderFontFamilyProperty); }
            set { this.SetValue(HeaderFontFamilyProperty, value); }
        }

        /// <summary>
        /// Gets or sets header font size
        /// </summary>
        public double HeaderFontSize
        {
            get { return (double)this.GetValue(HeaderFontSizeProperty); }
            set { this.SetValue(HeaderFontSizeProperty, value); }
        }

        /// <summary>
        /// Gets or sets header font style
        /// </summary>
        public FontStyle HeaderFontStyle
        {
            get { return (FontStyle)this.GetValue(HeaderFontStyleProperty); }
            set { this.SetValue(HeaderFontStyleProperty, value); }
        }
        
        /// <summary>
        /// Gets or sets header render transform
        /// </summary>
        public Transform HeaderRenderTransform
        {
            get { return (Transform)this.GetValue(HeaderRenderTransformProperty); }
            set { this.SetValue(HeaderRenderTransformProperty, value); }
        }

        /// <summary>
        /// Open charm setting
        /// </summary>
        public void Open()
        {
            this.popup.IsOpen = false;

            this.popup.IsOpen = true;
        }

        /// <summary>
        /// Close charm setting
        /// </summary>
        public void Close()
        {
            this.popup.IsOpen = false;
        }

        /// <summary>
        /// Dispose implementation
        /// </summary>
        public void Dispose()
        {
            if (this.popup != null)
            {
                this.popup = null;
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Fires when Fly out Width property changes
        /// </summary>
        /// <param name="source">The source</param>
        /// <param name="e">The argument</param>
        private static void OnSettingFlyoutWidth(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            (source as CharmSettingFlyout).InvalidateMeasure();
        }
        
        /// <summary>
        /// Fires when popup opened
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The argument</param>
        private void OnPopupOpened(object sender, object e)
        {
        }

        /// <summary>
        /// Fires when popup closed.
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The argument</param>
        private void OnPopupClosed(object sender, object e)
        {
            this.popup.Child = null;
            Window.Current.Activated -= this.OnCurrentWindowActivated;
        }

        /// <summary>
        /// Fires when current window is activated
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The argument</param>
        private void OnCurrentWindowActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
        {
            if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
            {
                this.popup.IsOpen = false;
            }
        }

        /// <summary>
        /// Occurs when a FrameworkElement has been constructed and added to the object tree
        /// </summary>
        /// <param name="sender">The source</param>
        /// <param name="e">Event data for the event</param>
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            Window.Current.Activated += this.OnCurrentWindowActivated;
            double popupLeft = SettingsPane.Edge == SettingsEdgeLocation.Right ? Window.Current.Bounds.Width - (double)this.FlyoutWidth : 0;
            this.popup.SetValue(Canvas.LeftProperty, popupLeft);

            Button backButton = this.GetTemplateChild("BackButton") as Button;

            backButton.Tapped += this.OnBackButtonTapped;
        }

        /// <summary>
        /// Fires when the back button is tapped. Hide charm setting and show the setting pane
        /// </summary>
        /// <param name="sender">The source</param>
        /// <param name="e">The argument</param>
        private void OnBackButtonTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
        {
            this.Close();

            SettingsPane.Show();
        }
    }
}